package com.xdjd.mobile.system.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gitee.easyopen.ApiContext;
import com.gitee.easyopen.ApiMeta;
import com.gitee.easyopen.ApiResult;
import com.gitee.easyopen.interceptor.ApiInterceptorAdapter;
import com.xdjd.mobile.business.entity.vo.LoginUser;
import com.xdjd.mobile.business.util.RedisTool;
import com.xdjd.mobile.business.util.ResponseUtil;
import com.xdjd.mobile.business.util.SpringContextUtils;
import com.xdjd.mobile.system.ApiUtil;
import com.xdjd.mobile.system.anotations.ApiAuth;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

/**
 * <pre>
 * 业务处理锁（防暴击）：
 * 同一个人同一时间只能处理一个业务。
 * </pre>
 *
 * @author tanghc
 */
public class LockInterceptor extends ApiInterceptorAdapter {

    private Logger logger = LoggerFactory.getLogger(getClass());

    // 拦截接口名当中有这些关键字的
    private static List<String> uriKeyList = Arrays.asList("challenge.user","user.clock.create","user.clock.add.bonus","user.step.update","friend.focus","friend.supervise","edit.user.info");

    private int lockExpireMilliseconds = 3000; // 锁过期时间，3秒

    private JedisPool jedisPool;

    public LockInterceptor() {
        jedisPool = SpringContextUtils.getBean(JedisPool.class);
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object serviceObj, Object argu)
            throws Exception {

        LoginUser loginUser = ApiUtil.getCurrentUser();
        String lockKey;
        String requestId;
        lockKey = this.getLockKey(loginUser);
        requestId = this.getRequestId(loginUser);
        Jedis jedis = jedisPool.getResource();

        try {
            boolean hasLock = RedisTool.tryGetDistributedLock(jedis, lockKey, requestId, lockExpireMilliseconds);
            // 如果没有取到锁，认为是暴击，直接返回
            if (!hasLock) {
                logger.warn("用户（{}）访问{}产生暴击！", loginUser.getAccount(), ApiContext.getApiParam().fatchNameVersion());
                ApiResult result = new ApiResult();
                result.setCode(-102);
                result.setMsg("您已提交，请耐心等待哦");
                ResponseUtil.renderJson(response, JSON.toJSONString(result));
                return false;
            }
        } finally {
            IOUtils.closeQuietly(jedis);
        }

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object serviceObj,
                                Object argu, Object result, Exception e) throws Exception {

        LoginUser loginUser = ApiUtil.getCurrentUser();

        String lockKey;
        String requestId;
        lockKey = this.getLockKey(loginUser);
        requestId = this.getRequestId(loginUser);
        Jedis jedis = jedisPool.getResource();
        try {
            RedisTool.releaseDistributedLock(jedis, lockKey, requestId);
        } finally {
            IOUtils.closeQuietly(jedis);
        }
    }

    private String getLockKey(LoginUser loginUser) {
        return "api_lock_key:" + String.valueOf(loginUser.getId());
    }

    private String getLockKey(String unionid) {
        return "api_lock_key:" + unionid;
    }

    private String getRequestId(LoginUser loginUser) {
        return "api_lock_request_id_" + loginUser.getId();
    }

    private String getRequestId(String unionid) {
        return "api_lock_request_id_" + unionid;
    }

    @Override
    public boolean match(ApiMeta apiMeta) {
        String name = apiMeta.getName();
        ApiAuth apiAuth = apiMeta.getMethod().getAnnotation(ApiAuth.class);
        if (name.startsWith("nologin") || apiAuth != null) {
            return false;
        }
        return uriKeyList.contains(name);
    }

}
